package com.atguigu.lease.web.admin.service.impl;

import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.model.entity.*;
import com.atguigu.lease.model.enums.ItemType;
import com.atguigu.lease.web.admin.mapper.*;
import com.atguigu.lease.web.admin.service.*;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentDetailVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentItemVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentQueryVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentSubmitVo;
import com.atguigu.lease.web.admin.vo.fee.FeeValueVo;
import com.atguigu.lease.web.admin.vo.graph.GraphVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import kotlin.jvm.internal.Lambda;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @author liubo
 * @description 针对表【apartment_info(公寓信息表)】的数据库操作Service实现
 * @createDate 2023-07-24 15:48:00
 */
@Service
public class ApartmentInfoServiceImpl extends ServiceImpl<ApartmentInfoMapper, ApartmentInfo>
        implements ApartmentInfoService {

    @Autowired
    private GraphInfoService graphInfoService;
    @Autowired
    private ApartmentLabelService apartmentLabelService;
    @Autowired
    private ApartmentFacilityService apartmentFacilityService;
    @Autowired
    private ApartmentFeeValueService apartmentFeeValueService;

    @Resource
    private ApartmentInfoMapper apartmentInfoMapper;
    @Resource
    private GraphInfoMapper graphInfoMapper;
    @Resource
    private LabelInfoMapper labelInfoMapper;
    @Resource
    private FacilityInfoMapper facilityInfoMapper;
    @Resource
    private FeeValueMapper feeValueMapper;
    @Resource
    private RoomInfoMapper roomInfoMapper;

    //TODO 保存或更新公寓信息
    @Override
    public void saveOrUpdateApartmentInfo(ApartmentSubmitVo apartmentSubmitVo) {
        /**
         * TODO ps：此处必须先获取isUpdate的值，再去执行公共操作
         *  因为如果传过来的id值是null，那么本来isUpdate是false，也就是新增操作
         *  此时如果先执行了saveOrUpdate，就会导致传过来的id的值被自动赋值（或是雪花id，或是自动递增，取决于自己的配置）
         *  综上，必须先执行isUpdate，然后再执行公共操作saveOrUpdate
         */
        //1.根据传递过来的id，判断是否为空，如果为空，那么说明是新增操作，如果不为空，说明是更新操作
        boolean isUpdate = apartmentSubmitVo.getId() != null;
        //2.此时我们获知了是否是更新或新增操作，但是不论是新增或是更新，都要完成部分公共操作，这里先完成公共操作saveOrUpdate
        this.saveOrUpdate(apartmentSubmitVo);
        //3.根据apartmentSubmitVo先获取传递过来的公寓id
        //TODO PS：因为上面执行了saveOrUpdate，所以不论原先的id是否为空，
        // 此时id都获得了值，因为saveOrUpdate执行完毕后，会给Vo对象赋值
        // 如果原先传入的id是null，也就是新增操作，那么在saveOrUpdate执行完后，id值就是自动赋值了的
        Long apartmentId = apartmentSubmitVo.getId();

        //TODO 如果判定成功是更新操作，那么就执行下面的代码

        if (isUpdate) {
            // TODO 4.接下来我们需要完成涉及中间表的操作，当然前提是要先判断是否是更新操作，如果不是，那么就不需要执行中间表的操作
            //4.1 【图片部分】删除原先Graph_info中和apartmentId有关的所有数据
            LambdaQueryWrapper<GraphInfo> graphInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            graphInfoLambdaQueryWrapper.eq(GraphInfo::getItemType, ItemType.APARTMENT)
                    .eq(GraphInfo::getItemId, apartmentId);
            graphInfoService.remove(graphInfoLambdaQueryWrapper);

            //4.2 【标签中间表】删除原先标签Apartment_lable中间表中和apartmentId有关的所有数据
            LambdaQueryWrapper<ApartmentLabel> labelLambdaQueryWrapper = new LambdaQueryWrapper<>();
            labelLambdaQueryWrapper.eq(ApartmentLabel::getApartmentId, apartmentId);
            apartmentLabelService.remove(labelLambdaQueryWrapper);

            //4.3 【配套中间表】删除原先配套Apartment_facility中间表中和apartmentId有关的所有数据
            LambdaQueryWrapper<ApartmentFacility> facilityLambdaQueryWrapper = new LambdaQueryWrapper<>();
            facilityLambdaQueryWrapper.eq(ApartmentFacility::getApartmentId, apartmentId);
            apartmentFacilityService.remove(facilityLambdaQueryWrapper);

            //4.4 【费用中间表】删除原先费用Apartment_fee_value中间表中和apartmentId有关的所有数据
            LambdaQueryWrapper<ApartmentFeeValue> feeValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
            feeValueLambdaQueryWrapper.eq(ApartmentFeeValue::getApartmentId, apartmentId);
            apartmentFeeValueService.remove(feeValueLambdaQueryWrapper);
        }
        // TODO 5.我们已经清空了旧的数据，下面开始添加新的数据
            //5.1 【图片部分】添加新的图片数据
            //5.1.1 先获取前端发送来的List图片集合
            List<GraphVo> graphVoList = apartmentSubmitVo.getGraphVoList();
            //5.1.2 创建出一个包含GraphInfo对象的集合List，用来存储待添加的数据，随后返回
            //TODO 先判断传来的graphVoList集合是否为空，如果不为空，才执行下面的操作
            if (!CollectionUtils.isEmpty(graphVoList)){
                List<GraphInfo> graphInfos = new ArrayList<>();
                //5.1.3 遍历graphVoList集合，装配出一个个GraphInfo对象，并且添加到graphInfos集合里面
                for (GraphVo graphVo : graphVoList) {
                    //5.1.4 创建出GraphInfo对象，用于装配信息并且装配进List集合中
                    GraphInfo graphInfo = new GraphInfo();
                    graphInfo.setName(graphVo.getName());
                    graphInfo.setUrl(graphVo.getUrl());
                    graphInfo.setItemType(ItemType.APARTMENT);
                    graphInfo.setItemId(apartmentId);
                    //5.1.5 对象装配完毕，现在将对象组装进List集合中
                    graphInfos.add(graphInfo);
                }
                //5.1.6 使用mybatis-plus的saveBatch方法，将新的图片List集合数据批量插入到数据库中
                graphInfoService.saveBatch(graphInfos);
            }


            //5.2 【标签部分】添加新的标签数据到中间表中
            //5.2.1 先获取前端发送来的标签ID的List集合
            List<Long> labelIds = apartmentSubmitVo.getLabelIds();
            //TODO 先判断传来的ID集合是否为空，如果不为空，才执行下面的操作
            if (!CollectionUtils.isEmpty(labelIds)){
                //5.2.2 创建一个包含AparmentLabel对象的List集合对象，用来存储待添加的数据，随后返回
                List<ApartmentLabel> apartmentLabelList = new ArrayList<>();
                //5.2.3 遍历标签id集合，往apartmentLabelList中装配一个个ApartmentLabel对象
                for (Long labelId : labelIds) {
                    ApartmentLabel apartmentLabel = ApartmentLabel.builder()
                            .apartmentId(apartmentId)
                            .labelId(labelId)
                            .build();
                    apartmentLabelList.add(apartmentLabel);
                }
                //5.2.4 调用mybatis-plus的saveBatch方法，将apartmentLabelList集合中的数据批量插入到数据库中
                apartmentLabelService.saveBatch(apartmentLabelList);
            }

            //5.3 【配套部分】添加新的配套数据到中间表中
            //5.3.1 先获取前端发送来的配套id集合
            List<Long> facilityInfoIds = apartmentSubmitVo.getFacilityInfoIds();
            //TODO 先判断传来的ID集合是否为空，如果不为空，才执行下面的操作
            if (!CollectionUtils.isEmpty(facilityInfoIds)){
                //5.3.2 提前创建一个List集合对象，用来存储待添加的数据，随后返回
                List<ApartmentFacility> apartmentFacilityList = new ArrayList<>();
                //5.3.3 遍历配套id集合
                for (Long facilityInfoId : facilityInfoIds) {
                    //5.3.4 创建ApartmentFacility对象，往里面装配数据，并且最后添加到List集合中
                    ApartmentFacility apartmentFacility = ApartmentFacility.builder()
                            .apartmentId(apartmentId)
                            .facilityId(facilityInfoId)
                            .build();
                    apartmentFacilityList.add(apartmentFacility);
                }
                //5.3.5 调用mybatis-plus的saveBatch方法，将apartmentFacilityList集合中的数据批量插入到数据库中
                apartmentFacilityService.saveBatch(apartmentFacilityList);
            }

            //5.4 【杂费部分】 添加新的杂费数据到中间表中
            //5.4.1 获取从前端发送的杂费值的id集合
            List<Long> feeValueIds = apartmentSubmitVo.getFeeValueIds();
            //TODO 先判断传来的ID集合是否为空，如果不为空，才执行下面的操作
            if (!CollectionUtils.isEmpty(feeValueIds)){
                //5.4.2 提前创建一个包含ApartmentFeeValue的对象集合，用来存储待添加的数据，随后返回
                List<ApartmentFeeValue> apartmentFeeValueList = new ArrayList<>();
                //5.4.3 遍历杂费id集合，往apartmentFeeValueList中装配一个个ApartmentFeeValue对象
                for (Long feeValueId : feeValueIds) {
                    //5.4.4 创建出ApartmentFeeValue对象，往里面装配数据，并且最后添加到List集合中
                    ApartmentFeeValue apartmentFeeValue = ApartmentFeeValue.builder()
                            .apartmentId(apartmentId)
                            .feeValueId(feeValueId)
                            .build();
                    //5.4.5 对象装配完毕，现在将对象组装进List集合中
                    apartmentFeeValueList.add(apartmentFeeValue);
                }
                //5.4.6 调用mybatis-plus的saveBatch方法，将apartmentFeeValueList集合中的数据批量插入到数据库中
                apartmentFeeValueService.saveBatch(apartmentFeeValueList);
            }
    }

    //TODO 分页查询公寓信息
    @Override
    public IPage<ApartmentItemVo> findApartmentItemVoPage(IPage<ApartmentItemVo> page, ApartmentQueryVo queryVo) {
        return apartmentInfoMapper.findApartmentItemVoPage(page,queryVo);
    }

    //TODO 根据id查询公寓的详情信息
    @Override
    public ApartmentDetailVo findApartmentDetailVoById(Long id) {
        //ApartmentDetailVo继承自ApartmentInfo
        //因此它由ApartmentInfo和4大属性
        //graphVoList,labelInfoList,facilityInfoList,feeValueVoList组成
        //所以要组装这个对象，就要获取5个值，给它set进去
        //TODO 1.根据id获取ApartmentInfo对象
        ApartmentInfo apartmentInfo = this.getById(id);
        //TODO 2.获取List<GraphVo>
        List<GraphVo> graphVoList = graphInfoMapper.findListByItemTypeAndId(ItemType.APARTMENT,id);
        //TODO 3.获取List<LabelInfo>
        List<LabelInfo> labelInfoList = labelInfoMapper.findListByApartmentId(id);
        //TODO 4.获取List<FacilityInfo>
        List<FacilityInfo> facilityInfoList = facilityInfoMapper.findListByApartmentId(id);
        //TODO 5.获取List<FeeValueVo>
        List<FeeValueVo> feeValueVoList = feeValueMapper.findListByApartmentId(id);
        //TODO 6.组装ApartmentDetailVo对象
        ApartmentDetailVo apartmentDetailVo = new ApartmentDetailVo();
        BeanUtils.copyProperties(apartmentInfo,apartmentDetailVo);
        apartmentDetailVo.setGraphVoList(graphVoList);
        apartmentDetailVo.setLabelInfoList(labelInfoList);
        apartmentDetailVo.setFacilityInfoList(facilityInfoList);
        apartmentDetailVo.setFeeValueVoList(feeValueVoList);
        return apartmentDetailVo;
    }

    @Override
    public void removeApartmentById(Long id) {
        //TODO 在删除公寓之前，先判断一下该公寓名下有没有房间，若存在房间信息
        // 那么就先不删除，先提醒用户应该先删除房间信息，再删除公寓信息
        LambdaQueryWrapper<RoomInfo> roomInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roomInfoLambdaQueryWrapper.eq(RoomInfo::getApartmentId,id);
        Long count = roomInfoMapper.selectCount(roomInfoLambdaQueryWrapper);
        //此时说明该公寓名下有房间信息，那么不能直接删除公寓信息，因此抛出自定义异常LeaseException
        if (count > 0){
            throw new LeaseException(ResultCodeEnum.DELETE_ERROR);
        }
        //1.删除graph_info表中的数据
        LambdaQueryWrapper<GraphInfo> graphInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        graphInfoLambdaQueryWrapper.eq(GraphInfo::getItemId,id)
                .eq(GraphInfo::getItemType,ItemType.APARTMENT);
        graphInfoService.remove(graphInfoLambdaQueryWrapper);
        //2.删除Apartment_facility中间表的数据
        LambdaQueryWrapper<ApartmentFacility> facilityLambdaQueryWrapper = new LambdaQueryWrapper<>();
        facilityLambdaQueryWrapper.eq(ApartmentFacility::getApartmentId,id);
        apartmentFacilityService.remove(facilityLambdaQueryWrapper);
        //3.删除Apartment_label中间表的数据
        LambdaQueryWrapper<ApartmentLabel> labelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        labelLambdaQueryWrapper.eq(ApartmentLabel::getApartmentId,id);
        apartmentLabelService.remove(labelLambdaQueryWrapper);
        //4.删除Apartment_fee_value中间表的数据
        LambdaQueryWrapper<ApartmentFeeValue> apartmentFeeValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
        apartmentFeeValueLambdaQueryWrapper.eq(ApartmentFeeValue::getApartmentId,id);
        apartmentFeeValueService.remove(apartmentFeeValueLambdaQueryWrapper);
        //5.删除apartmentInfo表中的数据
        this.removeById(id);
    }


}




